The present invention relates to a server application programming model using software components, and more particularly relates to enhancing scalability of server applications programmed as software components.
In many information processing applications, a server application running on a host or server computer in a distributed network provides processing services or functions for client applications running on terminal or workstation computers of the network which are operated by a multitude of users. Common examples of such server applications include software for processing class registrations at a university, travel reservations, money transfers and other services at a bank, and sales at a business. In these examples, the processing services provided by the server application may update databases of class schedules, hotel reservations, account balances, order shipments, payments, or inventory for actions initiated by the individual users at their respective stations.
An important consideration in many of these server applications is the ability to handle heavy processing loads. In the above server application examples, for instance, the updates for a large number of users may be submitted to the server application within a short time period. As each update may consume significant processing time, each additional user of the server application can slow the response or time to complete updates for all other users"" updates, thus reducing the quality of service for all users. Eventually, the load may exceed the processing capacity, possibly resulting in system failure, down time, and lost data. The degree to which a server application can support incremental increases in user load while preserving performance is sometimes referred to as scalability.
One factor that affects server application scalability is the server application""s use of memory to store user data while performing processing for that user. The server computer""s memory is a limited resource that is shared among all the users of the server application. Because server computer memory is a shared fixed resource, the duration that the server application stores one user""s data affects the availability of the memory to store other users"" data. By minimizing the duration that data is stored in the server computer memory for each user, the server application is able to support many more clients with a given server computer memory capacity.
One approach to enhancing scalability is for the server application to keep user data in memory only during the course of a single interaction or exchange with a client (e.g., while processing one remote procedure call or message exchange from the client). The server application keeps a current state of each user""s data (also referred to as the user""s xe2x80x9cstatexe2x80x9d) in secondary storage (e.g., hard disk and other large capacity storage devices), and loads the state into the server computer""s main memory only as long as necessary to perform a discrete processing operation on the data responsive to the single interaction. After completing processing of the single interaction, the server application again stores the state into secondary memory. This practice effectively shares the scarce main memory resources among the users. Using this practice, the server application can accommodate more users.
Under this xe2x80x9csurgical strikexe2x80x9d or xe2x80x9cget in/get outxe2x80x9d style of programming, the server application generally consisted of a group of functions or procedures that could be called remotely by client applications at the user""s workstations to perform the discrete processing operations in a single interaction between the client and server application. In general, the user""s state was loaded into main memory at the start of the function, and stored away at the function""s completion. Also, the function""s parameter list would contain all input data from the client application that was needed for the processing operation. This would sometimes lead to server application functions with extensive parameter lists. For example, a simple function in a banking server application for a money transfer might include parameters for the amount to be transferred, the account number to debit, the account number to credit, the authorization number, the check number, the teller id, the branch id, etc.
Programming models generally known as object-oriented programming provide many benefits that have been shown to increase programmers"" productivity, but are in many ways antithetical to the just discussed approach to enhancing scalability. In object-oriented programming, programs are written as a collection of object classes which each model real world or abstract items by combining data to represent the item""s properties with functions to represent the item""s functionality. More specifically, an object is an instance of a programmer-defined type referred to as a class, which exhibits the characteristics of data encapsulation, polymorphism and inheritance. Data encapsulation refers to the combining of data (also referred to as properties of an object) with methods that operate on the data (also referred to as member functions of an object) into a unitary software component (i.e., the object), such that the object hides its internal composition, structure and operation and exposes its functionality to client programs that utilize the object only through one or more interfaces. An interface of the object is a group of semantically related member functions of the object. In other words, the client programs do not access the object""s data directly, but must instead call functions on the object""s interfaces to operate on the data.
Polymorphism refers to the ability to view (i.e., interact with) two similar objects through a common interface, thereby eliminating the need to differentiate between two objects. Inheritance refers to the derivation of different classes of objects from a base class, where the derived classes inherit the properties and characteristics of the base class.
Object-oriented programming generally has advantages in ease of programming, extensibility, reuse of code, and integration of software from different vendors and (in some object-oriented programming models) across programming languages. However, object-oriented programming techniques generally are antithetical to the above-discussed approach to enhancing server application scalability by minimizing the duration of state to single client/server application interactions. In object-oriented programming, the client program accesses an object by obtaining a pointer or reference to an instance of the object in memory. The client program retains this object reference throughout the course of its interaction with the object, which allows the client program to call member functions on the object. So long as any client programs have a reference to an object""s instance, data associated with the instance is maintained in memory to avoid the client issuing a call to an invalid memory reference. At the very least, even where the client program calls only a single member function, the object instance is kept in memory between the client program""s initial call to request a reference to the object instance and the client program""s call to release the reference (between which the client program issues one or more calls to member functions of the object using the reference). In other words, the client program has control over the object""s lifetime. The object is kept in memory until the client""s reference to the object is released.
Also, object-oriented programming encourages setting an object""s properties using separate member functions. For example, a money transfer object may provide a set of member functions that includes a SetDebitAccount( ) function, a SetCreditAccount( ) function, a SetTransferAmount( ) function, etc. that the client program calls to set the object""s properties. Finally, the client program may call a TransferMoney( ) function to cause the object to perform the money transfer operation using the accumulated object properties (also referred to as the object""s state). Again, while the client program issues these separate calls, the object is maintained in memory. In a server application, this programming style can drastically reduce the server application""s scalability.
A further disadvantage of object-oriented programming of server applications is that each separate operation with or use of an object often requires creating a separate instance of the object. This is because the accumulated properties that are set for one operation with an object typically differ from the settings of the properties in another operation. In the above money transfer object example, for instance, separate money transfer operations usually involve different account numbers and transfer amounts. Since the accumulated state of an object is retained, the client program either instantiates a new instance of the object for a subsequent money transfer or carefully resets each property of the previously used object instance to avoid carrying properties set in the previous money transfer over to the subsequent transfer. However, instantiating each object also is expensive in terms of processing time and thus further reduces server application scalability.
The present invention is a component-based framework that provides scalable server applications using object-oriented programming principles. The component-based framework according to the invention supports deactivatable software components that conform to object-oriented programming principles. These components can be deactivated such that the component""s state is released from memory (i.e., in the sense that any state associated with an instance of the object is no longer kept in memory, nor written to disk as in a persistent object store) while a client program retains a reference to the component. The framework additionally supports just-in-time activation of the component where the component""s initial state is restored into memory upon the client program issuing a call to the component using the reference. This deactivation and just-in-time activation of the component has the advantage of minimizing memory usage by the components in a server application, which promotes scalability.
Deactivation allows reuse of the component by the client program in separate operations. The component is deactivated at the completion of an operation. Later, when the client again issues calls to the component for a subsequent operation, the framework automatically re-activates the component in its initial state. Since the component is restored to its initial state at activation, the client program can safely reuse the component with assurance that properties are not carried over from a previous operation with the component. The client program can continue its use of the component in repeated deactivation and just-in-time activation cycles. In effect, the framework thus provides a sequence or stream of instances of the component which the client program accesses through the retained component reference.
According to one aspect of the invention, the framework initially creates the component in a deactivated state and returns the component reference to the client when access to the component is first requested by the client program. The component is not activated until the client program first uses the component reference in a call to the component. This further reduces the time that the component""s state is held in memory.
According to a further aspect of the invention, the component controls when it can be deactivated. The framework provides an application programming interface (xe2x80x9cAPIxe2x80x9d) with which the component indicates upon return from a client program""s call that the component does not need to maintain its state after return from the call. On receiving this indication, the framework and component release any resources currently held by the component so that the resources may be reclaimed for other uses. This allows the framework to deactivate the component on an as-soon-as-possible basis, such as at the completion of an operation after which the component""s state (e.g., accumulated property settings) need not be retained.
In another aspect of the invention, the framework deactivates and activates the component in connection with transaction processing. Transaction processing is a well known technique for processing a collection of actions (referred to as a xe2x80x9ctransactionxe2x80x9d) as a single indivisible unit of work in accordance with the properties of atomicity, consistency, isolation, and durability (referred to as the xe2x80x9cACIDxe2x80x9d properties). (See, inter alia, Orfali, Robert et al., Essential Client/Server Survival Guide, pp. 241-260, John Wiley and Sons, Inc., 1994.) First, when the component completes its participation in a transaction, the component calls framework-provided application programming interface (xe2x80x9cAPIxe2x80x9d), such as a SetComplete( ) or SetAbort( ) function, to notify the framework that the component""s work on the transaction is successfully completed or must be aborted, and further that the component""s state can be released. In response, the framework can deactivate the component. Additionally, components participating in a transaction are automatically deactivated when the transaction commits or aborts. Again, this helps to free server memory and other server resources used by the component as soon as possible after the component completes its work in a transaction. Since instance state accumulated during the transaction is released, this also helps to maintain isolation of the transaction.
In yet another aspect of the invention, the framework recycles component instances to increase the efficiency of activation and deactivation. On deactivating a component instance, the framework may place the deactivated component instance into an instance pool. When activating a component, the framework uses an instance of the component from the pool if one is available. In those circumstances where an instance can be recycled from the pool, the framework saves the processing effort of creating a new instance of the component. On reactivation from the pool, the recycled component instance is returned to its initial activation state.